package com.machine.filling.net.serialPort.util;

import android.annotation.SuppressLint;
import android.os.Handler;
import android.os.Message;

import com.machine.filling.Test.TestCommon;
import com.machine.filling.util.FileUtils;
import com.machine.filling.util.LogUtil;
import com.machine.filling.util.StringUtil;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.ref.WeakReference;
import java.net.Socket;

import android_serialport_api.SerialPort;

/**
 * Created by Administrator on 2018/1/12 0012.
 * 串口工具类
 */

public class SerialPortTool {

    private static final String TAG = "SerialPortTool";
    /**
     * 读取串口数据
     */
    private static final int READ_DATA = 1001;
    /**
     * 串口 读数据 超时
     */
    private static final int PORT_READ_OUT_TIME = 1002;

    /**
     * 串口读取超时时间
     */
    private static final int OUT_TIME = 10 * 1000;

    /**
     * 计数器
     */
    private static int TIMES = 0;

    private String serialNum;//串口号（对应串口路径上的ttyS0）

    private String path = "/dev/";//串口路径 （硬件上管他叫设备名）
    private int baudrate = 9600;//波特率
    public boolean serialPortStatus = false; //是否打开串口标志
    public boolean threadStatus; //线程状态，为了安全终止线程

    public SerialPort serialPort = null;
    public InputStream inputStream = null;
    public OutputStream outputStream = null;

    private int bufferSize = 256;//缓冲区大小

    private static final String freamHead = "7EFE";

    private static final String freamEnd = "0D";
    private boolean isReading;

    public SerialPortTool(String serialNum) {
        this.serialNum = serialNum;
        path = "/dev/" + serialNum;
    }

    public boolean isFirst = true;

    public static final String HOST = "192.168.1.48";
    public static final int PORT = 8765;
    private static WeakReference<Socket> mSocket;

    public WeakReference<Socket> getSerialPort() {
        return mSocket;
    }

    /**
     * 打开socket
     */
    public void openSerialPort() {
        try {
            serialPort = new SerialPort(new File(path), baudrate, 0);
            this.serialPortStatus = true;
            threadStatus = false; //线程状态

            //获取打开的串口中的输入输出流，以便于串口数据的收发
            inputStream = serialPort.getInputStream();
            outputStream = serialPort.getOutputStream();
            new ReadThread().start(); //开始线程监控是否有数据要接收
        } catch (Exception e) {
            LogUtil.e(TAG, serialNum + " 打开串口异常：" + e.toString());
        }
    }


    public void closeSerialPort() {
        try {
            if (inputStream != null) {
                inputStream.close();
            }
            if (outputStream != null) {
                outputStream.close();
            }
            threadStatus = true;
            serialPortStatus = false;
            if (null != mSocket) {
                Socket sk = mSocket.get();
                if (!sk.isClosed()) {
                    sk.close();
                }
                sk = null;
                mSocket = null;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void sendSerialPort(String dataHex) {
        try {
            LogUtil.e("发送指令Center-->" + dataHex);
            byte[] sendData = StringUtil.hexStrTobytes(dataHex);
            if (sendData.length > 0) {
                if (outputStream != null) {
                    outputStream.write(sendData);
                    outputStream.flush();
                    LogUtil.d(TAG, System.currentTimeMillis() + "端口号-->" + serialNum + ": 串口数据发送成功");
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @SuppressLint("HandlerLeak")
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                //读取串口数据
                case READ_DATA:
                    String lastMsg = (String) msg.obj;
                    //                    LogUtil.d(TAG, "lastMsg: " + lastMsg);
                    //                    LogUtil.d(TAG, "serialNum: " + serialNum);
                    if (!StringUtil.isNullOrEmpty(serialNum) && !StringUtil.isNullOrEmpty(lastMsg)
                            && onSerialPortDataReceiveListener != null) {
                        //末尾校验，长度校验，crc校验
                        onSerialPortDataReceiveListener.onDataReceive(serialNum, lastMsg, System.currentTimeMillis());
                    }
                    result = "";
                    break;
                //读取操作与返回数据 时间间隔
                case PORT_READ_OUT_TIME:
                    LogUtil.d(TAG, "handleMessage() returned: " + serialNum + "连接超时");
                    Message outTimeMsg = Message.obtain();
                    outTimeMsg.what = PORT_READ_OUT_TIME;
                    outTimeMsg.obj = System.currentTimeMillis();
                    mHandler.sendMessageDelayed(outTimeMsg, 2000);
                    //todo 此处暂时注释掉;因员工卡加油后,选择支付方式的时候,读取不到任何数据,此时与离线状态一致,容易混淆
                    //                    onSerialPortDataReceiveListener.onPortOffLineOutTime(DateUtils.getCurrentTimeYMDHMS(), serialNum);
                    break;
            }
        }
    };

    //这是写了一监听器来监听接收数据
    public OnSerialPortDataReceiveListener onSerialPortDataReceiveListener = null;

    public interface OnSerialPortDataReceiveListener {
        /**
         * 串口连接成功,返回数据
         *
         * @param serialNum           串口号
         * @param hexStr              读取到的串口数据
         * @param currentTimeMillions
         */
        void onDataReceive(String serialNum, String hexStr, long currentTimeMillions);

        /**
         * 串口离线
         *
         * @param time
         * @param portNum
         */
        void onPortOffLineOutTime(String time, String portNum);
    }

    public void setOnSerialPortDataReceiveListener(OnSerialPortDataReceiveListener onSerialPortDataReceiveListener) {
        this.onSerialPortDataReceiveListener = onSerialPortDataReceiveListener;
    }

    /**
     * 测试用的 模拟串口数据
     */
    public void testSimulateSerialPort() {
        final Handler handler = new Handler();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                onSerialPortDataReceiveListener.onDataReceive(serialNum, TestCommon.TEST_SERIAL_DATA, System.currentTimeMillis());
                handler.postDelayed(this, 2000);
            }
        };
        handler.postDelayed(runnable, 2000);
    }

    /**
     * 单开一线程，来读数据   (包含拆包,合并.  如果含有两条命令连在一起的情况,需要拆包 ; 如果含有一条命令有多帧,需要合并)
     */
    String result = "";

    private class ReadThread extends Thread {
        @Override
        public void run() {
            super.run();
            String lastMsg = "";//完整帧
            int allMsgLength;
            //判断进程是否在运行，更安全的结束进程
            while (!threadStatus) {
                //64   1024
                byte[] buffer = new byte[bufferSize];
                int size; //读取数据的大小
                try {
                    size = readMessage(inputStream, buffer);
                    if (size > 0) {
                        String currMsg = StringUtil.bytesToHexString(buffer).substring(0, 2 * size).toUpperCase();
                        if (result.endsWith("0d") || result.endsWith("0D")) {
                            if (result.contains("7e") || result.contains("7E")) {
                                //                                readResult(result);
                                //                                LogUtil.d("接收数据-->" + result);
                                //                                parse(result);
                                FileUtils.saveFile(null, "读取[" + result + "]", true);
                                lastMsg = result;
                                Message msg = Message.obtain();
                                msg.obj = lastMsg;
                                msg.what = READ_DATA;
                                mHandler.sendMessage(msg);
                            }
                        } else if (currMsg.startsWith("7e") || currMsg.startsWith("7E")) {
                            result = "";
                            result += currMsg;
                            //                            LogUtil.e("开头-->"+ result);
                        } else {
                            result += currMsg;
                            //                            LogUtil.e("中间-->"+ result);
                        }
                    }
                } catch (Exception e) {
                    LogUtil.e(TAG, serialNum + "run: 数据读取异常：-------------------------------------------------------------------" + e.toString());
                }
            }
        }

    }

    public void parse(String hexStr) {

    }

    /**
     * 读取数据, 每次读取 都发送一个超时时间的handler消息
     *
     * @param ins
     * @param buf
     * @throws Exception
     */
    public int readMessage(InputStream ins, byte[] buf) throws Exception {
        Message msg = Message.obtain();
        msg.what = PORT_READ_OUT_TIME;
        msg.obj = TIMES++;
        mHandler.sendMessageDelayed(msg, OUT_TIME);
        int size = ins.read(buf);
        mHandler.removeMessages(PORT_READ_OUT_TIME);
        return size;
    }

    /**
     * TODO
     * 解析接收到的byte
     *
     * @param hexStr
     */
    public void readResult(String hexStr) {
        //7EFE100621040B000000000000000000028581730D
        String state = hexStr.substring(8, 12);
        switch (state) {
            case "2104":
//                LogUtil.e("空闲");
                break;
            case "8101":
                LogUtil.e("加油前准备");
                break;
            case "2101":
                LogUtil.e("加油结束");
                break;
            case "9108":
                LogUtil.e("脱机状态");
                break;
            case "2105":
                LogUtil.e("加油机回复");
                break;
            case "1105":
                LogUtil.e("查询总累");
                break;
            case "2102":
                LogUtil.e("加油机回复查询总累");
                break;
            case "1104":
                LogUtil.e("设置油机");
                break;
            case "910E":
                LogUtil.e("设置屏参");
                break;
            case "910C":
                LogUtil.e("设置显示屏广告信息");
                break;
            case "1102":
                LogUtil.e("锁机");
                break;
            case "1003":
                LogUtil.e("解锁");
                break;
            case "1101":
                LogUtil.e("下发卡信息");
                break;
            case "9101":
                LogUtil.e("下发写卡信息");
                break;
            case "1002":
                LogUtil.e("下发交易确认信息");
                break;
            default:
        }
    }

}
